home *** CD-ROM | disk | FTP | other *** search
/ APDL Other Worlds / APDL Other Worlds Collection.iso / SF3000 / Extras / !SFskyedit / c / Back-end next >
Encoding:
Text File  |  2003-10-16  |  10.1 KB  |  312 lines

  1. /*
  2.  *  SFskyedit - Star Fighter 3000 sky colours editor
  3.  *  Back-end functions
  4.  *  Copyright (C) 2001  Chris Bazley
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public Licence as published by
  8.  *  the Free Software Foundation; either version 2 of the Licence, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public Licence for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public Licence
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* ANSI library files */
  22. #include <stdbool.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <assert.h>
  27.  
  28. /* RISC OS library files */
  29. #include "kernel.h"
  30. #include "flex.h"
  31.  
  32. /* My library files */
  33. #include "err.h"
  34. #include "msgtrans.h"
  35. #include "Macros.h"
  36. #include "SFformats.h"
  37.  
  38. /* Local headers */
  39. #include "Utils.h"
  40. #include "Back-end.h"
  41. #include "Main.h"
  42.  
  43. char *clipboard = NULL;
  44. int clipboard_size = 0;
  45.  
  46. /* ----------------------------------------------------------------------- */
  47. /*                         Public functions                                */
  48.  
  49. bool copy_to_clipboard(SF_SkyColours **sky, int start_band, int end_band)
  50. {
  51.   wipe_clipboard();
  52.  
  53.   clipboard_size = (end_band - start_band) + 1;
  54.   if(!flex_alloc((flex_ptr)&clipboard, clipboard_size))
  55.     MG_RETV("NoMem", false); /* failed */
  56.  
  57.   for(int band = 0; band < clipboard_size; band++)
  58.     clipboard[band] = get_shade(sky, (start_band + band));
  59.  
  60.   return true; /* success */
  61. }
  62.  
  63. /* ----------------------------------------------------------------------- */
  64.  
  65. char get_shade(SF_SkyColours **sky, int pos)
  66. {
  67.   assert(pos >= 0 && pos <= 62);
  68.   return ((*sky)->shade[1+(pos*2)] & 0xff); /* success */
  69. }
  70.  
  71. /* ----------------------------------------------------------------------- */
  72.  
  73. void write_shade(SF_SkyColours **sky, int pos, char mode13col)
  74. {
  75.   /* Write shade to table with dithered transitions above and below */
  76.   unsigned int mask1 = 0xff00ff00;
  77.   unsigned int mask2 = 0x00ff00ff;
  78.   unsigned int fullword = mode13col | (mode13col << 8) | (mode13col << 16) | (mode13col << 24);
  79.  
  80.   assert(pos >= 0 && pos <= 62);
  81.  
  82.   /* Set plain colour */
  83.   (*sky)->shade[1+(pos*2)] = fullword;
  84.  
  85.   /* Dither with preceding colour */
  86.   if(pos > 0) {
  87.     (*sky)->shade[pos*2] = ((*sky)->shade[1 + ((pos-1)*2)] & mask1)
  88.                       | (fullword & mask2);
  89.   }
  90.   else
  91.     (*sky)->shade[pos*2] = fullword;
  92.  
  93.   /* Dither with following colour */
  94.   if(pos == 62)
  95.     return;
  96.   (*sky)->shade[(pos+1)*2] = ((*sky)->shade[1 + ((pos+1)*2)] & mask2)
  97.                         | (fullword & mask1);
  98. }
  99.  
  100. /* ----------------------------------------------------------------------- */
  101.  
  102. void smooth_section(SF_SkyColours **sky, int start_band, int end_band)
  103. {
  104.   int last_trans, centre, last_centre;
  105.   last_trans = start_band;
  106.  
  107.   for(int row = (start_band+1); row <= end_band; row++) {
  108.  
  109.     if(get_shade(sky, row) != get_shade(sky, last_trans)) { /* transition detected! */
  110.  
  111.       /* Check for first transition (e.g. where none prior */
  112.       if(last_trans != start_band) {
  113.         /* Calculate centrepoint of previous colour area */
  114.         centre = last_trans + ((row - last_trans)/2);
  115.  
  116.         /* Re-paint transition between previous area and preceeding one */
  117.         if((centre - last_centre) > 2)
  118.           gradient_overwrite(sky, last_centre, centre, get_shade(sky, last_centre), get_shade(sky, centre), 3);
  119.  
  120.         /* init search for next transition / centre of new area */
  121.         last_centre = centre;
  122.       }
  123.       else
  124.         /* For first gradient, pretend that first row is prev centre */
  125.         last_centre = start_band;
  126.       last_trans = row;
  127.     }
  128.   }
  129.   if(last_trans == start_band)
  130.     return; /* not one transition!! */
  131.  
  132.   /* To smooth to last row, pretend that it is a final centre */
  133.   if((end_band - last_centre) > 2)
  134.     gradient_overwrite(sky, last_centre, end_band, get_shade(sky, last_centre), get_shade(sky, end_band), 3);
  135. }
  136.  
  137. /* ----------------------------------------------------------------------- */
  138.  
  139. void insert_from_clipboard(SF_SkyColours **sky, int start_band)
  140. {
  141.   open_gap(sky, start_band, clipboard_size);
  142.   for(int band = 0; band < clipboard_size && (start_band + band) < 63; band++)
  143.     write_shade(sky, (start_band + band), clipboard[band]);
  144. }
  145.  
  146. /* ----------------------------------------------------------------------- */
  147.  
  148. void wipe_clipboard(void)
  149. {
  150.   if(clipboard != NULL)
  151.     flex_free((flex_ptr)&clipboard);
  152.   clipboard = NULL;
  153.   clipboard_size = 0;
  154. }
  155.  
  156. /* ----------------------------------------------------------------------- */
  157.  
  158. void open_gap(SF_SkyColours **sky, int start_band, int size)
  159. {
  160.   /* Copy bands up to make room */
  161.   for(int band = 62; band >= (start_band + size); band--)
  162.     write_shade(sky, band, get_shade(sky, band-size));
  163. }
  164.  
  165. /* ----------------------------------------------------------------------- */
  166.  
  167. void remove_bands(SF_SkyColours **sky, int start_band, int end_band)
  168. {
  169.   /* Copy bands down squashing offending ones */
  170.   int size = (end_band - start_band) + 1;
  171.   for(int band = start_band; band < 63; band++) {
  172.     if(band + size < 63)
  173.       write_shade(sky, band, get_shade(sky, band + size));
  174.     else
  175.       /* Black out newly exposed space at top */
  176.       write_shade(sky, band, 0);
  177.   }
  178. }
  179.  
  180. /* ----------------------------------------------------------------------- */
  181.  
  182. void plain_insert(SF_SkyColours **sky, int start_band, int size, char mode13col)
  183. {
  184.   /* Insert new colour bands with specified shade */
  185.   if(size < 1)
  186.     return;
  187.  
  188.   open_gap(sky, start_band, size);
  189.   plain_overwrite(sky, start_band, start_band+(size-1), mode13col);
  190. }
  191.  
  192. /* ----------------------------------------------------------------------- */
  193.  
  194. void plain_overwrite(SF_SkyColours **sky, int start_band, int end_band, char mode13col)
  195. {
  196.   /* Change colour bands to specified shade */
  197.   if(start_band < 0)
  198.     start_band = 0;
  199.   if(end_band > 62)
  200.     end_band = 62;
  201.  
  202.   for(int band = start_band; band <= end_band; band++)
  203.     write_shade(sky, band, mode13col);
  204. }
  205.  
  206. /* ----------------------------------------------------------------------- */
  207.  
  208. void gradient_insert(SF_SkyColours **sky, int start_band, int size, char start_col, char end_col, unsigned int end_flags)
  209. {
  210.   /* Insert gradient fill between specified colours */
  211.   if(size < 1)
  212.     return;
  213.   open_gap(sky, start_band, size);
  214.   gradient_overwrite(sky, start_band, start_band+(size-1), start_col, end_col, end_flags);
  215. }
  216.  
  217. /* ----------------------------------------------------------------------- */
  218.  
  219. void gradient_overwrite(SF_SkyColours **sky, int start_band, int end_band, char start_col, char end_col, unsigned int end_flags)
  220. {
  221.   /* Write gradient fill between specified colours
  222.      end_flags b0 = include start colour
  223.                b1 = include end colour */
  224.  
  225. #ifndef NDEBUG
  226.   {char string[256];
  227.   sprintf(string, "report start col:%d target col:%d flags:%d", start_col, end_col, end_flags);
  228.   _kernel_oscli(string);}
  229. #endif
  230.  
  231.   int dist = end_band - start_band;
  232.   if(FLAG_SET(end_flags, 1u<<0)) {
  233.     /* Include start colour */
  234.     if(start_band >= 0 && start_band <= 62)
  235.       write_shade(sky, start_band, start_col); /* write start shade */
  236.     start_band++;
  237.   } else
  238.     dist++; /* an extra step (initial colour not drawn) */
  239.  
  240.   if(FLAG_SET(end_flags, 1u<<1)) {
  241.     /* Include end colour */
  242.     if(end_band >= 0 && end_band <= 62)
  243.       write_shade(sky, end_band, end_col); /* write end shade */
  244.     end_band--;
  245.   } else
  246.     dist++; /* an extra step (final colour not drawn) */
  247.  
  248.   if(dist <= 0)
  249.     return; /* guard against division by zero */
  250.  
  251.   /* Get 24-bit palette entries for start/end colours */
  252.   unsigned int first_paletteentry = palette[start_col];
  253.   unsigned int last_paletteentry = palette[end_col];
  254.  
  255.   /* Calculate initial R/G/B values and increments for smooth gradient */
  256.   float red_component = (float)((first_paletteentry & 0x0000ff00) >> 8);
  257.   int red_diff = ((last_paletteentry & 0x0000ff00) >> 8) - (int)red_component;
  258.   float red_inc = (float)red_diff/(float)dist;
  259. #ifndef NDEBUG
  260.   {char string[256];
  261.   sprintf(string, "report RED start=%f distance=%d increment=%f", red_component,red_diff,red_inc);
  262.   _kernel_oscli(string);}
  263. #endif
  264.  
  265.   float green_component = (float)((first_paletteentry & 0x00ff0000) >> 16);
  266.   int green_diff = ((last_paletteentry & 0x00ff0000) >> 16) - (int)green_component;
  267.   float green_inc = (float)green_diff/(float)dist;
  268. #ifndef NDEBUG
  269.   {char string[256];
  270.   sprintf(string, "report GREEN start=%f distance=%d increment=%f", green_component,green_diff,green_inc);
  271.   _kernel_oscli(string);}
  272. #endif
  273.  
  274.   float blue_component = (float)((first_paletteentry & 0xff000000) >> 24);
  275.   int blue_diff = ((last_paletteentry & 0xff000000) >> 24) - (int)blue_component;
  276.   float blue_inc = (float)blue_diff/(float)dist;
  277. #ifndef NDEBUG
  278.   {char string[256];
  279.   sprintf(string, "report BLUE start=%f distance=%d increment=%f", blue_component,blue_diff,blue_inc);
  280.   _kernel_oscli(string);}
  281. #endif
  282.  
  283.   /* Write colour gradient... */
  284.   for(int band = start_band; band <= end_band; band++) {
  285.  
  286.     /* Calculate transitional colour */
  287.     red_component += red_inc;
  288.     green_component += green_inc;
  289.     blue_component += blue_inc;
  290. #ifndef NDEBUG
  291.     {char string[256];
  292.     sprintf(string, "report ideal colour for band %d is R=%f G=%f B=%f", band, red_component, green_component, blue_component);
  293.     _kernel_oscli(string);
  294.     char near = real_to_mode13col(((unsigned int)blue_component<<24) | ((unsigned int)green_component<<16) | ((unsigned int)red_component<<8));
  295.     sprintf(string, "report nearest mode 13 colour:%d (R=%d G=%d B=%d)", near, (palette[near] & 0xff00)>>8, (palette[near] & 0xff0000)>>16, (palette[near] & 0xff000000)>>24);
  296.     _kernel_oscli(string);}
  297. #endif
  298.  
  299.     /* Write nearest to ideal colour in default mode 13 palette */
  300.     if(band >= 0 && band <= 62)
  301.       write_shade(
  302.         sky,
  303.         band,
  304.         real_to_mode13col(
  305.           ((unsigned int)blue_component<<24) |
  306.           ((unsigned int)green_component<<16) |
  307.           ((unsigned int)red_component<<8)
  308.         )
  309.       );
  310.   } /* next band */
  311. }
  312.